import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5 import uic
from core.BaslerCommunication import BaslerCam
import numpy as np
import pyqtgraph as pg
import time
from imageProcess import boldProcess
from PyQt5.QtSql import QSqlDatabase, QSqlTableModel, QSqlQuery, QSqlQueryModel
import datetime


imageCalculations = dict()
imageCentre = list()


class CentrePosition(QObject):
    '''
    定义中心位置信号
    '''
    centrePosition = pyqtSignal(tuple)

class ImageProcess(QRunnable):
    '''
    图像处理线程
    '''
    def __init__(self, image):
        super().__init__()
        self.image = image
        self.signals = CentrePosition()    #创建一个信号类的实例
        # self.query = sql

    @pyqtSlot()
    def run(self):
        centerimage = boldProcess.blodprocess(self.image)
        # print(type(centerimage[0]))
        # self.query.prepare('INSERT INTO centriod (Xg_1,Yg_1,Xg_2,Yg_2) VALUES (:Xg_1, :Yg_1, :Xg_2, :Yg_2)')
        # self.query.bindValue(':Xg_1', float(centerimage[0]))
        # self.query.bindValue(':Yg_1', float(centerimage[0]))
        # self.query.bindValue(':Xg_2', 100)
        # self.query.bindValue(':Yg_2', 100)
        # self.query.exec()
        self.signals.centrePosition.emit(centerimage)

class CentreNum(QRunnable):
    '''
    用于判断数值是否达标,如1000
    '''
    def __init__(self, centrefile):
        super().__init__()
        self.centrefile = centrefile

    @pyqtSlot()
    def run(self):
        if len(imageCentre) == 10:
            # print('进行保存')
            self.centrefile.writelines(imageCentre)
            imageCentre.clear()


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.bcamera = None  # 记录相机开启bite
        self.darkimage = []
        # pg.setConfigOption('background','w')    #设置pg图像的背景色

        self.threadpool = QThreadPool()
        print('线程最大值：%d' %self.threadpool.maxThreadCount())

        self.ui = uic.loadUi('./graphicsshow.ui', self)  # 继承UI
        self.init_ui()
        self.init_cam()
        self.init_sql()
        self.scene = QGraphicsScene(self)
        self.setupCamList()  # 获取连接的相机列表，在combo中显示出来
        self.combo_Cam.activated.connect(self.pushButtonOpenEnable)  # 当在combo中选中一款相机后,激活打开相机按钮
        self.pushButton_open_cam.clicked.connect(self.openCam)
        self.pushButton_dark.clicked.connect(self.darkProcess)
        self.pushButton_exit.clicked.connect(self.close)  # 退出按钮，退出程序
        self.lineEdit_exposure.returnPressed.connect(self.setExposure)  # 输入框设置曝光
        self.Slider_exposure.valueChanged.connect(self.changeExposureText)  # 滑块设置曝光
        self.pushButton_acquisition.toggled.connect(self.Acquisition)  # 获取或取消获取图片
        self.lineEdit_gain.returnPressed.connect(self.setGain)  # 输入框设置增益
        self.Slider_gain.valueChanged.connect(self.changGainText)  # 滑块设置增益
        self.pushButton_auto_exposure.toggled.connect(self.autoExposure)  # 自动曝光按钮
        self.pushButton_auto_gain.toggled.connect(self.autoGain)  # 自动增益按钮
        self.check_analysis.toggled.connect(self.analysisEnable)  #分析按钮
        self.comboBox_pixelformat.currentIndexChanged.connect(self.pixelformat)    #设置相机的像素模式
        self.Slider_width.valueChanged.connect(self.sliderWidthValueChanged)
        self.Slider_height.valueChanged.connect(self.sliderHeightValueChanged)
        self.Slider_xoffset.valueChanged.connect(self.sliderXoffsetValueChanged)
        self.Slider_yoffset.valueChanged.connect(self.sliderYoffsetValueChanged)
        self.spinBox_width.valueChanged.connect(self.spinBoxWidthValueChanged)
        self.spinBox_xoffset.valueChanged.connect(self.spinBoxXoffsetValueChanged)
        self.spinBox_height.valueChanged.connect(self.spinBoxHeightValueChanged)
        self.spinBox_yoffset.valueChanged.connect(self.spinBoxYoffsetValueChanged)
        self.Slider_targetgray.valueChanged.connect(self.sliderTargetgrayValueChanged)
        self.spinBox_targetgray.valueChanged.connect(self.spinBoxTargetgrayValueChanged)
        try:
            self.cam.imageArrived.connect(self.onReceiveImage)  # 接收来自相机的图片，并显示在graphicsView升级后的控件中，注意，这里使用的ImageEvent触发
            # self.ImageSend
        except:
            pass

    def init_cam(self):
        try:
            self.cam = BaslerCam()
            print('初始化成功')
        except:
            pass

    def init_sql(self):
        self.db = QSqlDatabase.addDatabase('QMYSQL')
        self.db.setHostName('127.0.0.1')
        self.db.setPort(3306)
        self.db.setUserName('root')
        self.db.setPassword('123456')
        self.db.setDatabaseName('demodb')
        # self.db.setConnectOptions()
        self.db.open()
        if self.db.open():
            print('成功打开数据库')
            self.query = QSqlQuery()
        else:
            print(self.db.lastError().text())


    def setupCamList(self):
        try:
            self.combo_Cam.clear()
            CamList = self.cam.returnCamList()
            for cam in CamList:
                self.combo_Cam.addItem(cam)
        except:
            pass


    def sliderTargetgrayValueChanged(self):
        self.cam.setTargetgrayValue(self.Slider_targetgray.value())
        self.spinBox_targetgray.setValue(self.Slider_targetgray.value())

    def spinBoxTargetgrayValueChanged(self):
        self.Slider_targetgray.setValue(self.spinBox_targetgray.value())

    def sliderWidthValueChanged(self):
        # self.Slider_xoffset.setMaximum(self.cam.getWidthHeightMinMax()[1] - self.Slider_width.value())
        # self.spinBox_xoffset.setMaximum(self.cam.getWidthHeightMinMax()[1] - self.Slider_width.value())
        self.Slider_xoffset.setMaximum(2048 - self.Slider_width.value())
        self.spinBox_xoffset.setMaximum(2048 - self.Slider_width.value())
        self.spinBox_width.setValue(self.Slider_width.value())
        self.cam.setCameraWidth(self.Slider_width.value())

    def sliderXoffsetValueChanged(self):
        self.Slider_width.setMaximum(2048 - self.Slider_xoffset.value())
        self.spinBox_width.setMaximum(2048 - self.Slider_xoffset.value())
        self.spinBox_xoffset.setValue(self.Slider_xoffset.value())
        self.cam.setCameraXoffset(self.Slider_xoffset.value())

    def sliderHeightValueChanged(self):
        self.Slider_yoffset.setMaximum(2048 - self.Slider_height.value())
        self.spinBox_yoffset.setMaximum(2048 - self.Slider_height.value())
        self.spinBox_height.setValue(self.Slider_height.value())
        self.cam.setCameraHeight(self.Slider_height.value())

    def sliderYoffsetValueChanged(self):
        self.Slider_height.setMaximum(2048 - self.Slider_yoffset.value())
        self.spinBox_height.setMaximum(2048 - self.Slider_yoffset.value())
        self.spinBox_yoffset.setValue(self.Slider_yoffset.value())
        self.cam.setCameraYoffset(self.Slider_yoffset.value())

    def spinBoxWidthValueChanged(self):
        self.Slider_width.setValue(self.spinBox_width.value())

    def spinBoxXoffsetValueChanged(self):
        self.Slider_xoffset.setValue(self.spinBox_xoffset.value())

    def spinBoxHeightValueChanged(self):
        self.Slider_height.setValue(self.spinBox_height.value())

    def spinBoxYoffsetValueChanged(self):
        self.Slider_yoffset.setValue(self.spinBox_yoffset.value())

    def pixelformat(self):
        self.cam.setPixelFormat(self.comboBox_pixelformat.currentText())

    def Acquisition(self):
        print('*获取')
        if self.pushButton_acquisition.isChecked():
            print('**获取')
            self.cam.getPic()
            self.pushButton_acquisition.setText('关闭图像获取')
            self.num = 0
            # self.starttime = time.time()
        else:
            self.cam.stopPic()
            self.pushButton_acquisition.setText('获取图像')

    @pyqtSlot(np.ndarray)
    def onReceiveImage(self, image):
        # self.num += 1
        # end = time.time()
        # print('******',self.num/(end-self.starttime))
        # imagep = ImageProcess(image - self.darkimage)
        imagep = ImageProcess(image)
        imagep.signals.centrePosition.connect(self.setCentre)
        self.threadpool.start(imagep)
        self.calculateCenter(image)
        self.update_CamImage(image)

    def setCentre(self, centrePositions):
        imageCentre.append(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')+','+str(centrePositions)[1:-1]+'\n')
        # imageCentre.append(str(centrePositions)[1:-1] + '\n')

        self.tableWidget_centroid.setItem(0, 0, QTableWidgetItem(str(centrePositions[0])))
        self.tableWidget_centroid.setItem(0, 1, QTableWidgetItem(str(centrePositions[1])))
        self.tableWidget_centroid.setItem(1, 0, QTableWidgetItem(str(centrePositions[2])))
        self.tableWidget_centroid.setItem(1, 1, QTableWidgetItem(str(centrePositions[3])))
        self.tableWidget_centroid.setItem(2, 0, QTableWidgetItem(str(centrePositions[4])))
        self.tableWidget_centroid.setItem(2, 1, QTableWidgetItem(str(centrePositions[5])))
        self.xCenter.setValue(float(centrePositions[1]))
        self.yCenter.setValue(float(centrePositions[0]))
        self.xCenter1.setValue(float(centrePositions[3]))
        self.yCenter1.setValue(float(centrePositions[2]))
        self.xCenter2.setValue(float(centrePositions[5]))
        self.yCenter2.setValue(float(centrePositions[4]))
        centreNum = CentreNum(self.centrefile)
        self.threadpool.start(centreNum)


    def calculateCenter(self, image):
        imageCalculations["SumY"] = np.max(image, axis=0)
        imageCalculations["SumX"] = np.max(image, axis=1)
        # imageCalculations["Center_X"] = len(imageCalculations["SumX"]) / 2
        # imageCalculations["Center_Y"] = len(imageCalculations["SumY"]) / 2

    def update_CamImage(self, image):
        self.Image.setImage(image, levels=(0, 255))
        self.progress_imagemax.setValue(np.max(image))
        if self.check_analysis.isChecked():
            self.curve.setData(x=imageCalculations["SumY"], y=np.arange(len(imageCalculations["SumY"])))
            self.curve2.setData(imageCalculations["SumX"])



    def autoGain(self):
        if self.pushButton_auto_gain.isChecked():
            print('进入到自动增益设置')
            self.pushButton_auto_gain.setText('关闭自动增益')
            self.lineEdit_gain.setFocusPolicy(Qt.NoFocus)
            self.Slider_gain.setDisabled(True)
            self.setAutoGain(True)
            print(self.cam.getGain())
        else:
            self.pushButton_auto_gain.setText('开启自动增益')
            self.lineEdit_gain.setFocusPolicy(Qt.StrongFocus)
            self.Slider_gain.setDisabled(False)
            self.setAutoGain(False)
            print(self.cam.getGain())

    def setAutoGain(self, state):
        self.cam.autoGain(state)

    def test(self):
        print('*')

    def autoExposure(self):
        print('按钮被点击了吗')
        # 启动了自动曝光
        if self.pushButton_auto_exposure.isChecked():
            print('开启自动曝光1')
            self.pushButton_auto_exposure.setText('关闭自动曝光')
            self.lineEdit_exposure.setDisabled(True)
            self.Slider_exposure.setDisabled(True)
            self.setAutoExposure(True)

        # 关闭了自动曝光
        else:
            self.pushButton_auto_exposure.setText('启动自动曝光')
            self.lineEdit_exposure.setDisabled(False)
            self.Slider_exposure.setDisabled(False)
            self.setAutoExposure(False)

    def setAutoExposure(self, state):
        self.cam.autoExposure(state)

    def getCurrentCam(self):
        return {0: str(self.combo_Cam.currentText())}

    def pushButtonOpenEnable(self):
        self.pushButton_open_cam.setEnabled(True)

    def openCam(self):
        if self.bcamera:
            self.cam.close()
        self.cam.openCommunications(self.getCurrentCam())

        self.initImageMaxRange()
        self.initExposureTimeRange()
        self.initGainRange()
        self.initWidthHeightRange()
        self.initTargetgrayRange()  # 获取链接后，设置一些控件的范围

    def initImageMaxRange(self):
        min, max = self.cam.returnPixelRange()
        self.progress_imagemax.setRange(min, max)

    def initExposureTimeRange(self):
        min, max = self.cam.returnExposureTimeRange()
        self.Slider_exposure.setRange(min, max)

    def initGainRange(self):
        min, max = self.cam.returnGainRange()
        self.Slider_gain.setRange(min, max)

    def initWidthHeightRange(self):
        print(self.cam.getWidthHeightMinMax())
        self.Slider_width.setRange(1, 2048)
        self.Slider_height.setRange(1, 2048)
        self.Slider_width.setValue(2048)
        self.Slider_height.setValue(2048)
        self.Slider_xoffset.setValue(0)
        self.Slider_yoffset.setValue(0)

        self.spinBox_width.setRange(1, 2048)
        self.spinBox_width.setValue(2048)
        self.spinBox_xoffset.setMaximum(0)
        self.spinBox_xoffset.setValue(self.Slider_xoffset.value())
        self.spinBox_height.setRange(1, 2048)
        self.spinBox_height.setValue(2048)
        self.spinBox_yoffset.setMaximum(0)
        self.spinBox_yoffset.setValue(self.Slider_yoffset.value())

        self.cam.setCameraXoffset(0)
        self.cam.setCameraYoffset(0)
        self.cam.setCameraHeight(2048)
        self.cam.setCameraWidth(2048)

    def initTargetgrayRange(self):
        min, max = self.cam.returnTargetgrayValueRange()
        self.spinBox_targetgray.setRange(min, max)
        self.Slider_targetgray.setRange(min, max)

    def setExposure(self):
        self.Slider_exposure.setValue(int(self.lineEdit_exposure.text()))

    def changeExposureText(self, value):
        # np.round(a,b),返回a后面小数点b，四舍五入的值
        print(value)
        self.lineEdit_exposure.setText(str(self.Slider_exposure.value()))
        try:
            self.cam.setExposure(value)
            print('设置硬件的曝光时间完毕')
        except Exception as e:
            print('改变设备的曝光时间错误：%s' % e)


    def setGain(self):
        # print(type(self.lineEdit_gain.text()))
        self.Slider_gain.setValue(int(self.lineEdit_gain.text()))

    def changGainText(self, value):
        self.lineEdit_gain.setText(str(self.Slider_gain.value()))
        try:
            self.cam.setGain(value)
            print('设置硬件的增益完毕')
        except Exception as e:
            print('改变设备的增益错误：%s' % e)

    def init_ui(self):
        self.centrefile = open('centrePosition2.txt', 'a')

        self.tableWidget_centroid.setRowCount(3)
        self.tableWidget_centroid.setColumnCount(2)
        self.pushButton_open_cam.setEnabled(False)
        #为graphicsLayoutWidget添加viewbox;row=0和col=0，就相当于matplotlib中指定画图位置，如2*2的图，指定位置为（0，0）的位置给它
        self.viewbox = self.ImageBox.addViewBox(row=0, col=0)
        self.viewbox.setAspectLocked(True) #锁定viewbox形状为正方形
        self.Image = pg.ImageItem() #创建一个ImageItem，用于存储图片

        #x轴与y轴无线延长线，用于标记某点的位置
        self.xCenter = pg.InfiniteLine(pen=(215, 0, 26), angle=90)
        self.yCenter = pg.InfiniteLine(pen=(215, 0, 26), angle=0)

        self.xCenter1 = pg.InfiniteLine(pen=(233, 204, 211), angle=90)
        self.yCenter1 = pg.InfiniteLine(pen=(233, 204, 211), angle=0)

        self.xCenter2 = pg.InfiniteLine(pen=(52, 108, 156), angle=90)
        self.yCenter2 = pg.InfiniteLine(pen=(52, 108, 156), angle=0)

        #把ImageItem添加到viewbox中
        self.viewbox.addItem(self.Image)

        # 限制区块的大小，restrict size of plot areas，https://groups.google.com/g/pyqtgraph/c/aMaCMOrrrJg
        self.ImageBox.ci.layout.setColumnMaximumWidth(1, 100)
        self.ImageBox.ci.layout.setRowMaximumHeight(1, 100)

    def analysisEnable(self):
        if self.check_analysis.isChecked():
            self.enableAnalysis()
        else:
            self.disableAnalysis()

    def enableAnalysis(self):
        # 注意这里的row和col，代表这个视图里的位置
        self.PlotY = self.ImageBox.addPlot(row=0, col=1)
        self.PlotX = self.ImageBox.addPlot(row=1, col=0)
        # 强制中央的viewox和两侧的绘图有坐标匹配机制
        self.PlotX.setXLink(self.Image.getViewBox())
        self.PlotY.setYLink(self.Image.getViewBox())

        #限制区块的大小，restrict size of plot areas，https://groups.google.com/g/pyqtgraph/c/aMaCMOrrrJg
        self.ImageBox.ci.layout.setColumnMaximumWidth(1, 100)
        self.ImageBox.ci.layout.setRowMaximumHeight(1, 100)

        self.viewbox.addItem(self.xCenter)
        self.viewbox.addItem(self.yCenter)
        self.viewbox.addItem(self.xCenter1)
        self.viewbox.addItem(self.yCenter1)
        self.viewbox.addItem(self.xCenter2)
        self.viewbox.addItem(self.yCenter2)

        self.addFitPlot()

    def disableAnalysis(self):
        self.viewbox.removeItem(self.xCenter)
        self.viewbox.removeItem(self.yCenter)
        self.removeFitPlots()

        self.ImageBox.removeItem(self.PlotY)
        self.ImageBox.removeItem(self.PlotX)

    def addFitPlot(self):
        self.curve = self.PlotY.plot(pen=(215, 128, 26), name='Integral')
        self.curve2 = self.PlotX.plot(pen=(215, 128, 26), name='Integral')
        self.curve6 = self.PlotX.plot(pen=(255, 0, 0), name='Fit')
        self.curve7 = self.PlotY.plot(pen=(255, 0, 0), name='Fit')
        self.sliceY = self.PlotY.plot(pen=(215, 125, 50), name='Slice')
        self.sliceX = self.PlotX.plot(pen=(215, 125, 50), name='Slice')
        self.XCenter0 = self.PlotX.addLine(x=0, movable=True, pen=(215, 0, 26))
        self.YCenter0 = self.PlotY.addLine(y=0, movable=True, pen=(215, 0, 26))

    def removeFitPlots(self):
        self.PlotY.clear()
        self.PlotX.clear()

    def darkProcess(self):
        self.darkimage = self.cam.grabdark()
        print('******',self.darkimage.shape)

    def closeEvent(self, event):
        try:
            # self.cam.linshicamBeginAcquisition()
            self.cam.close()
            self.db.close()
            self.centrefile.close()
        except Exception as e:
            print('Error %s' % e)
        super().closeEvent(event)




if __name__ == '__main__':
    app = QApplication(sys.argv)
    # #print(QStyleFactory.keys())
    app.setStyle('Fusion')
    wnd = MainWindow()
    wnd.setGeometry(
        QStyle.alignedRect(
            Qt.LeftToRight,
            Qt.AlignCenter,
            wnd.size(),
            app.desktop().availableGeometry()
        )
    )
    print('结尾')
    wnd.show()
    sys.exit(app.exec_())
